/*****************************************************************************
*
*  PROJECT:     SlipStream
*               (CLighting - Cg Lighting Class)
*  LICENSE:     GNU General Public License v3 - http://www.gnu.org/licenses/gpl.html

*  DEVELOPERS:  Philip Farquharson 	<B00137077@studentmail.uws.ac.uk>
*				John Gray 			<B00145524@studentmail.uws.ac.uk>		
*				Zohaib Bhatti		<B00104280@studentmail.uws.ac.uk>
*				Euan Hislop 		<B00138636@studentmail.uws.ac.uk>
*
*****************************************************************************/

#include "CLighting.h"
#include "cmath"

CGcontext cgContext;							// Create the Cg Context for the program
CGprofile cgVertexProfile, cgFragProfile;		// Create the hardware profiles
CGprogram cgVertProg, cgFragProg;				// Create the vertex and fragment programs
CGparameter modelViewProj, 						// Create the Cg Parameter for the model view matrix
		modelMatrix, 
		invTransModelMatrix, 
		La, Ld, Ls, lightPos, 
		Ke, Ka, Kd, Ks, eyePos1,
		shininess;	

//Variables for the MD5 model
GLfloat lightAmbient[] = {0.3f,0.2f,0.1f,1.0f};
GLfloat lightDiffuse[] = {1.0f,1.0f,1.0f,1.0f};
GLfloat lightSpecular[] = {1.0f,1.0f,1.0f,1.0f};
GLfloat lightPosition[] = {-2.0f,3.0f,5.0f,0.0f};
GLfloat matEmissive[] = {0.0,0.0,0.0,0.0};
GLfloat matAmbient[] = {0.3,0.0,1.0,1.0};
GLfloat matDiffuse[] = {0.4,0.8,1.0,1.0};
GLfloat matSpecular[] = {1.0,1.0,1.0,1.0};
GLfloat matShininess[] = {60.0f };

GLfloat rot = 0;

int CLighting::init()
{
	// Create Cg Context Beginning
	cgContext = cgCreateContext();

	if(cgContext == NULL)
	{
		MessageBox(NULL, "Failed to create Cg context", "Error", MB_OK);
		return false;
	}
	// Create Cg Context End

	m_yRotation = 0;
	
	// Create Cg Profiles Beginning
	cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);

	if(cgVertexProfile == CG_PROFILE_UNKNOWN)
	{
		MessageBox(NULL, "Invalid vertex profile type", "Error", MB_OK);
		return false;
	}

	cgFragProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);

	if(cgFragProfile == CG_PROFILE_UNKNOWN)
	{
		MessageBox(NULL, "Invalid fragment profile type", "Error", MB_OK);
		return false;
	}
	// Create Cg Profiles End


	
	// Create Cg Programs Beginning
	cgGLSetOptimalOptions(cgVertexProfile);
	cgGLSetOptimalOptions(cgFragProfile);

	cgVertProg = cgCreateProgramFromFile(cgContext, CG_SOURCE, "vsLighting.cg", cgVertexProfile, "main", 0);
	cgFragProg = cgCreateProgramFromFile(cgContext, CG_SOURCE, "fsLighting.cg", cgFragProfile, "main", 0);

	if(cgVertProg == NULL || cgFragProg == NULL)
	{
		CGerror Error = cgGetError();

		MessageBox(NULL, cgGetErrorString(Error), "Error", MB_OK);
		return false;
	}

	cgGLLoadProgram(cgVertProg);
	cgGLLoadProgram(cgFragProg);
	// Create Cg Programs End



	// Shader Parameter Loading Beginning
	modelViewProj = cgGetNamedParameter(cgVertProg, "modelViewProj");

	if(modelViewProj == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'modelViewProj'", "Error", MB_OK);
		return false;
	}

	modelMatrix = cgGetNamedParameter(cgVertProg, "modelMatrix");

	if(modelMatrix == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'modelMatrix'", "Error", MB_OK);
		return false;
	}

	invTransModelMatrix = cgGetNamedParameter(cgVertProg, "invTransModelMatrix");

	if(invTransModelMatrix == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'invTransModelMatrix'", "Error", MB_OK);
		return false;
	}
	
	La = cgGetNamedParameter(cgFragProg, "La");

	if(La == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'La'", "Error", MB_OK);
		return false;
	}
	
	Ld = cgGetNamedParameter(cgFragProg, "Ld");

	if(Ld == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Ld'", "Error", MB_OK);
		return false;
	}
	
	Ls = cgGetNamedParameter(cgFragProg, "Ls");

	if(Ls == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Ls'", "Error", MB_OK);
		return false;
	}
	
	lightPos = cgGetNamedParameter(cgFragProg, "lightPos");

	if(lightPos == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'lightPos'", "Error", MB_OK);
		return false;
	}

	Ke = cgGetNamedParameter(cgFragProg, "Ke");

	if(Ke == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Ke'", "Error", MB_OK);
		return false;
	}

	Ka = cgGetNamedParameter(cgFragProg, "Ka");

	if(Ka == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Ka'", "Error", MB_OK);
		return false;
	}

	Kd = cgGetNamedParameter(cgFragProg, "Kd");

	if(Kd == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Kd'", "Error", MB_OK);
		return false;
	}

	Ks = cgGetNamedParameter(cgFragProg, "Ks");

	if(Ks == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'Ks'", "Error", MB_OK);
		return false;
	}

	eyePos1 = cgGetNamedParameter(cgFragProg, "eyePos");

	if(eyePos1 == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'eyePos'", "Error", MB_OK);
		return false;
	}

	shininess = cgGetNamedParameter(cgFragProg, "shininess");

	if(shininess == NULL)
	{
		MessageBox(NULL, "Couldn't find parameter 'shininess'", "Error", MB_OK);
		return false;
	}
	// Shader Parameter Loading End

	return true;

}

void CLighting::modelLighting(GLfloat modelXPosition, GLfloat modelYPosition, GLfloat modelZPosition, GLfloat modelXRotation, GLfloat modelYRotation, GLfloat modelZRotation, GLfloat modelScale)
{
	cgGLBindProgram(cgVertProg);
	cgGLEnableProfile(cgVertexProfile); // Enable the vertex shader profile
	cgGLBindProgram(cgFragProg);
	cgGLEnableProfile(cgFragProfile); // Enable the fragment shader profile

	lightPosition[0] -= 0.1;

	rot += 0.5;

	cgGLSetParameter3fv(La, lightAmbient);
	cgGLSetParameter3fv(Ld, lightDiffuse);
	cgGLSetParameter3fv(Ls, lightSpecular);
	cgGLSetParameter3fv(lightPos, lightPosition);
	cgGLSetParameter3fv(Ke, matEmissive);
	cgGLSetParameter3fv(Ka, matAmbient);
	cgGLSetParameter3fv(Kd, matDiffuse);
	cgGLSetParameter3fv(Ks, matSpecular);
	cgGLSetParameter1f(shininess, matShininess[0]);
	
	// calculate lights new position
	lightPosition[0] +=  sin(m_yRotation * (3.14/180)) * 2;
	lightPosition[2] +=  cos(m_yRotation * (3.14/180)) * 2;

	glPushMatrix(); // save the modelview matrix

		glLoadIdentity();

		// Perform the transformations currently applied to the model
		glTranslatef(modelXPosition, modelYPosition, modelZPosition);
		glRotatef(modelXRotation, 1.0f, 0.0f, 0.0f);
		glRotatef(modelYRotation, 0.0f, 1.0f, 0.0f);
		glRotatef(rot, 0.0f, 0.0f, 1.0f);
		glScalef(modelScale, modelScale, modelScale);

		cgGLSetStateMatrixParameter(modelMatrix, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);
		cgGLSetStateMatrixParameter(invTransModelMatrix, CG_GL_MODELVIEW_MATRIX,CG_GL_MATRIX_INVERSE_TRANSPOSE );

	glPopMatrix();
	glPushMatrix();

		// Perform the transformations currently applied to the model
		glTranslatef(modelXPosition, modelYPosition, modelZPosition);
		glRotatef(modelXRotation, 1.0f, 0.0f, 0.0f);
		glRotatef(modelYRotation, 0.0f, 1.0f, 0.0f);
		glRotatef(modelZRotation, 0.0f, 0.0f, 1.0f);
		glScalef(modelScale, modelScale, modelScale);

		m_yRotation += 0.5f;

		cgGLSetStateMatrixParameter(modelViewProj, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);

	glPopMatrix(); // revert back to the real modelview matrix
}
void CLighting::EndProfile(){

	cgGLDisableProfile(cgVertexProfile); // Disable the vertex profile
	cgGLDisableProfile(cgFragProfile);	 // Disable the frag profile
}
